﻿namespace Parser

open Lexer.Tocken

module ParserTable=

    type Terminal = Type

    type NonTerminal = 
        | S
        | Ret_S
        | If_S
        | Else_S
        | S_l
        | Param_l
        | Param_l'
        | Con_E
        | Pri_E
        | E
        | E'
        | Id_l
        | Id_l'
        | Def_S
        | Def_S'
        | A
        | Id_S
        | Id_S'
        | B

    type Symbol = 
        | Terminal of Terminal
        | NonTerminal of NonTerminal
        | Epsilon
        | Error

    let getSymbolName (s:Symbol) = 
        match s with
        | Terminal ter -> ter.ToString()
        | NonTerminal nonter -> nonter.ToString()
        | Epsilon -> Epsilon.ToString()
        | Error -> Error.ToString()


    let parserTable =  
        //Map<NonTerminal, Map<Terminal, seq<Symbol>>>
        Map <| seq {
        (S, Map <| seq{
            (ID, seq {NonTerminal(Id_S) })
            (INT, seq {NonTerminal( Def_S) })
            (RETURN, seq {NonTerminal( Ret_S )})
            (IF, seq {NonTerminal( If_S )})})
        (Id_S, Map <| seq{
            (ID, seq {Terminal(ID); NonTerminal(Id_S')})})
        (Def_S, Map <| seq {
            (INT, seq {Terminal(INT); Terminal(ID); NonTerminal(Def_S')})})
        (Def_S', Map <| seq {
            (AS, seq{Terminal(AS); Terminal(NUM); Terminal(SEM)})
            (LP, seq{Terminal(LP); NonTerminal(A)})})
        (Ret_S, Map <| seq {
            (RETURN, seq {Terminal(RETURN);  NonTerminal(E); Terminal(SEM)})})

        (If_S, Map <| seq {
            // if, if(Con_E){S_l}Else_E
            (IF, seq{
                Terminal(IF)
                Terminal(LP)
                NonTerminal(Con_E)
                Terminal(RP)
                Terminal(LBS)
                NonTerminal(S_l)
                Terminal(RBS)
                NonTerminal(Else_S)
            })
        })

        (Else_S, Map <| seq {
            // else, else {S_l}
            (ELSE, seq {
                Terminal(ELSE)
                Terminal(LBS)
                NonTerminal(S_l)
                Terminal(RBS)
            })
            // epsilon
            (END, seq {Epsilon})
        })

        (S_l, Map <| seq {
            // ID, S S_l
            (ID, seq {
                NonTerminal(S)
                NonTerminal(S_l)
            })
            // INT, S S_l
            (INT, seq {
                NonTerminal(S)
                NonTerminal(S_l)
            })
            // IF, S S_l
            (IF, seq {
                NonTerminal(S)
                NonTerminal(S_l)
            }) // RETURN, S S_l
            (RETURN, seq {
                NonTerminal(S)
                NonTerminal(S_l)
            })
            // RBS, epsilon
            (RBS, seq {
                Epsilon
            })
            // END, epsilon
            (END, seq {
                Epsilon
            })
        })

        (Param_l, Map <| seq {
            // INT, int id param_l'
            (INT, seq{
                Terminal(INT)
                Terminal(ID)
                NonTerminal(Param_l')
            })
        })

        (Param_l', Map <| seq {
            // COM, , int id param_l'
            (COM, seq {
                Terminal(COM)
                Terminal(INT)
                Terminal(ID)
                NonTerminal(Param_l')
            })
            // ), e
            (RP, seq {
                Epsilon
            })
        })

        (Id_l, Map <| seq {
            // ID ::= id id_l'
            (ID, seq {
                Terminal(ID)
                NonTerminal(Id_l')
            })
        })

        (Id_l', Map <| seq {
            (ID, seq {
                Terminal(ID)
            })
            // COM ::= ,id_l
            (COM, seq {
                Terminal(COM)
                NonTerminal(Id_l)
            })
        })

        (Con_E, Map <| seq {
            // ID, E relop E
            (ID, seq {
                NonTerminal(E)
                Terminal(RELOP)
                NonTerminal(E)
            })
            // NUM, E relop E
            (NUM, seq {
                NonTerminal(E)
                Terminal(RELOP)
                NonTerminal(E)
            })
            // LP, E relop E
            (LP, seq {
                NonTerminal(E)
                Terminal(RELOP)
                NonTerminal(E)
            })
            
        })

        (Pri_E, Map <| seq {
            (ID, seq {
                Terminal(ID)
            })
            (NUM, seq {
                Terminal(NUM)
            })
            // LP, (E)
            (LP, seq {
                Terminal(LP)
                NonTerminal(E)
                Terminal(RP)
            })
        })

        (E, Map <| seq {
            // ID ::=  pri_E E'
            (ID, seq {
                NonTerminal(Pri_E)
                NonTerminal(E')
            })
            (NUM, seq {
                NonTerminal(Pri_E)
                NonTerminal(E')
            })
            (LP, seq {
                NonTerminal(Pri_E)
                NonTerminal(E')
            })
        })

        (E', Map <| seq {
            (ADD, seq {
                Terminal(ADD)
                NonTerminal(Pri_E)
            })
            (SEM, seq {Epsilon})
            (RP, seq {Epsilon})
            (RELOP, seq {Epsilon})
            (END, seq{Epsilon})
        })

        (A, Map<| seq {
            // INT ::= param_l) {S_l}
            (INT, seq {
                NonTerminal(Param_l)
                Terminal(RP)
                Terminal(LBS)
                NonTerminal(S_l)
                Terminal(RBS)
            })
            // RP ::= ) {S_l}
            (RP, seq {
                Terminal(RP)
                Terminal(LBS)
                NonTerminal(S_l)
                Terminal(RBS)
            })
        })

        (B, Map <| seq {
            // ID ::= id-l)
            (ID, seq {
                NonTerminal(Id_l)
                Terminal(RP)
            })
            // RP ::=RP
            (RP, seq {
                Terminal(RP)
            })
        })

        (Id_S', Map <| seq {
            // AS ::= =E;
            (AS, seq {
                Terminal(AS)
                NonTerminal(E)
                Terminal(SEM)
            })
            // LP ::= (B
            (LP, seq {
                Terminal(LP)
                NonTerminal(B)
            })
        })
 }